﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using UnityEngine;
using System.Data;

//这是东华接受数据的工具类
public class SocketReceiveData
{
    Socket s;//定义Socket
    Thread thReceiveBuffer;//接受数据的线程
    Thread thDealBuffer;//处理缓存的线程
    Thread thDealPackData;//处理包数据的线程
    object m_lock = new object();//给线程加锁
    int cmbSend = 0;
    //定义数据缓存的容量
    const int ReceiveDataCount = 4096 * 4;
    const int PacketHeadSize = 12;
    int nNetPos = 0;
    //网络缓存数据
    List<byte> m_NetData = new List<byte>();
    //处理缓存数据
    byte[] m_TmpData;
    //所有缓存的包数据
    List<PackData> m_lstPackData = new List<PackData>();
    //所有待处理的包数据
    List<PackData> m_lstDealPackData = new List<PackData>();

    bool m_bThreadStop = false;
    byte[] recvData;
    static string tableName = "DHdata";
    //查询数据库中是否存在某表的参数
    #region
    string tablesql = $"SELECT * FROM information_schema.TABLES where table_name='DHdata' and TABLE_SCHEMA='db01';";
    #endregion
    string tablecountsql = $"SELECT COUNT(*) FROM DHdata;";
    //创建数据库的参数
    #region
    string tablename = "DHdata";
    string[] CloumName = new string[]
    {
        "id","Time","sensing","res"
    };
    string[] cloumtype = new string[]
    {
        "varchar(255)","datetime","varchar(255)","varchar(255)"
    };
    #endregion

    //删除数据库的参数
    #region
    string[] whereCloumsde = { "''" };

    string[] valuede = { "''" };

    #endregion

    //创建一个MySqlAcces对象
    public MySqlAcces SqlAcces;
    ///构造方法
    /// <summary>
    /// <param sqlAcces="_host">创建的MySqlAcces对象</param>
    /// </summary>
    public SocketReceiveData(MySqlAcces Sql_Acces)
    {
        SqlAcces = Sql_Acces;
    }

    //连接的函数
    public void StartServer_Click(string ip, int port)
    {
        try
        {
            //步骤1 配置远程服务器信息
            IPEndPoint removeServer = new IPEndPoint(IPAddress.Parse(ip), port);//通过配置文件
            //步骤2 创建套接字
            s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //步骤3 套接字连接远程服务器
            s.Connect(removeServer);
            //步骤4 提示连接状态
            if (s.Connected)
            {
                Debug.Log("连接服务器成功!");
                m_bThreadStop = false;
                recvData = new byte[ReceiveDataCount];
                try
                {
                    //步骤5 循环接收服务器发来的消息
                    thReceiveBuffer = new Thread(new ThreadStart(ReceiveData));
                    thReceiveBuffer.IsBackground = true;
                    thReceiveBuffer.Start();

                    thDealBuffer = new Thread(new ThreadStart(DealData));
                    thDealBuffer.IsBackground = true;
                    thDealBuffer.Start();

                    thDealPackData = new Thread(DealPackData);
                    thDealPackData.IsBackground = true;
                    thDealPackData.Start();

                    GetSignalInfo();
                }
                catch
                {
                    Debug.Log("失败!");
                }
            }
            else
            {
                Debug.Log("连接服务器失败!");
            }
        }
        catch
        {
            Debug.Log("连接服务器失败!");
        }
    }

    //清理
    private void btnClear_Click()
    {
        //txtInfo.Text = "";
        //txtSignalInfo.Text = "";
    }

    /// <summary>
    /// 接收数据
    /// </summary>
    void ReceiveData()
    {
        while (!m_bThreadStop)
        {
            try
            {
                int nRecvCount = s.Receive(recvData); //接收数据，返回每次接收的字节总数              
                if (nRecvCount > 0)
                {
                    byte[] tmp = new byte[nRecvCount];
                    Array.Copy(recvData, tmp, nRecvCount);
                    lock (m_lock)
                    {
                        m_NetData.AddRange(tmp);
                    }
                }
            }
            catch (Exception ex)
            {
                Debug.Log("ReceiveData Catch>>" + DateTime.Now + ex.StackTrace + ex.Message);
            }
        }
    }

    /// <summary>
    /// 处理数据
    /// </summary>
    void DealData()
    {
        while (!m_bThreadStop)
        {
            ParseBuffer();
            if (m_lstPackData.Count == 0)
            {
                Thread.Sleep(100);
            }
            lock (m_lock)
            {
                m_lstDealPackData.AddRange(m_lstPackData);
                m_lstPackData.Clear();
                //处理完包数据后，将m_NetData中用过的数据清除
                // 一直到 位置nNetPos 的m_NetData的数据已经用过
                m_NetData.RemoveRange(0, nNetPos);
                nNetPos = 0;               
            }
        }
    }

    /// <summary>
    /// 处理完整包数据
    /// </summary>
    void DealPackData()
    {
        while (!m_bThreadStop)
        {
            if (m_lstDealPackData.Count == 0)
            {
                Thread.Sleep(100);
            }

            while (m_lstDealPackData.Count > 0)
            {
                DealComData(m_lstDealPackData[0]);
                lock (m_lock)
                {
                    m_lstDealPackData.RemoveAt(0);
                }
            }
        }
    }

    /// <summary>
    /// 处理缓存数据
    /// </summary>
    void ParseBuffer()
    {
        if (m_NetData.Count <= nNetPos)
            return;

        lock (m_lock)//给线程加锁
        {
            m_TmpData = new byte[m_NetData.Count - nNetPos];
            Array.Copy(m_NetData.ToArray(), nNetPos, m_TmpData, 0, (m_NetData.Count - nNetPos));
        }

        int nAlreadyRecCount = m_TmpData.Length;
        if (nAlreadyRecCount <= 0)
            return;

        // 查找包文头信息
        for (int i = 0; i < m_TmpData.Length - 3; i++)
        {
            if (m_TmpData[i] == 0x55 && m_TmpData[i + 1] == 0xaa && m_TmpData[i + 2] == 0xaa && m_TmpData[i + 3] == 0x55)
            {
                FindPackHead(nAlreadyRecCount, i);
            }
        }
    }

    /// <summary>
    /// 找到包头标志后，对数据进行处理
    /// </summary>
    /// <param name="nAlreadyRecCount">接收的数据长度</param>
    /// <param name="nDataPointer">第几个字节开始为包头位置</param>
    void FindPackHead(int nAlreadyRecCount, int nDataPointer)
    {
        // 找到一个数据报头信息
        // 网络包长度小于包头时不是一个完整的包
        if (nAlreadyRecCount - nDataPointer < PacketHeadSize)
            return;

        PackHead m_PackHead = new PackHead();
        SetPackHead(nDataPointer, ref m_PackHead);

        // 判断获得的数据除去表头 是否大于数据长度
        if (nAlreadyRecCount - nDataPointer - PacketHeadSize < m_PackHead.DataLength)
            return;

        //完整的包数据
        byte[] m_ComData = new byte[PacketHeadSize + m_PackHead.DataLength];
        Array.Copy(m_TmpData, nDataPointer, m_ComData, 0, PacketHeadSize + m_PackHead.DataLength);

        PackData pd = new PackData();
        pd.m_Index = m_lstPackData.Count;
        pd.m_Head = m_PackHead;
        pd.m_ByteData = m_ComData.ToList();

        lock (m_lock)
        {
            nNetPos += PacketHeadSize + pd.m_Head.DataLength;
            m_lstPackData.Add(pd);
        }
    }

    /// <summary>
    /// 设置包头
    /// </summary>
    void SetPackHead(int nDataPointer, ref PackHead m_PackHead)
    {
        m_PackHead.Reset();
        m_PackHead.m_Signature[0] = m_TmpData[nDataPointer];
        m_PackHead.m_Signature[1] = m_TmpData[nDataPointer + 1];
        m_PackHead.m_Signature[2] = m_TmpData[nDataPointer + 2];
        m_PackHead.m_Signature[3] = m_TmpData[nDataPointer + 3];
        m_PackHead.m_Command[0] = m_TmpData[nDataPointer + 4];
        m_PackHead.m_Command[1] = m_TmpData[nDataPointer + 5];
        m_PackHead.m_Command[2] = m_TmpData[nDataPointer + 6];
        m_PackHead.m_Command[3] = m_TmpData[nDataPointer + 7];
        m_PackHead.m_Length[0] = m_TmpData[nDataPointer + 8];
        m_PackHead.m_Length[1] = m_TmpData[nDataPointer + 9];
        m_PackHead.m_Length[2] = m_TmpData[nDataPointer + 10];
        m_PackHead.m_Length[3] = m_TmpData[nDataPointer + 11];

        m_PackHead.DataLength = BitConverter.ToInt32(m_PackHead.m_Length, 0);
        m_PackHead.DataCommand = BitConverter.ToInt32(m_PackHead.m_Command, 0);
    }

    /// <summary>
    /// 处理完整包数据
    /// </summary>
    void DealComData(PackData pd)
    {
        string txtres = "";
        string txtSignalInfo = "";
        string res = "";//就是传递过来的数据
        int idcount = 0;
        switch (pd.m_Head.DataCommand)
        {
            case 128:
                res = DealCmd.DealGetSignal(pd);
                txtSignalInfo += "Commond 128  信号类型：" + pd.m_SignalType + ";内容:" + res + Environment.NewLine;
                break;
            case 123:
                res = DealCmd.DealTransferDataSignal(pd);
                txtres += "Commond 123  信号类型：" + pd.m_SignalType + ";信号名称:" + res + Environment.NewLine;
                break;
            case 124:
                res = DealCmd.DealSerialData(pd);
                txtres += "Commond 124Serial  信号位置：" + pd.m_Position + ";数据量:" + pd.m_DataCount + ";信号数："
                    + pd.m_SignalCount + Environment.NewLine + "数据：" + res + Environment.NewLine;
                break;
            case 125:
                res = DealCmd.DealStatData(pd);
                txtres += "Commond 125Stat  信号数：" + pd.m_SignalCount + ";数据：" + res + Environment.NewLine;
                break;
            case 126:
                res = DealCmd.DealBlockData(pd);
                txtres += "Commond 126Block  信号字符串长度：" + pd.m_SignalNameLength + ";信号名:" + pd.m_SignalName
                        + ";一个数据中包含几个float：" + pd.m_YCount + ";数据量：" + pd.m_DataCount + ";数据：" + res + Environment.NewLine;
                break;
        }

        try
        {
            //这是窗体的Invoke函数，调用委托的一种方法
            PrintRecvMssgDelegate printRecvMssgDelegate = new PrintRecvMssgDelegate(PrintRecvMssg);
            printRecvMssgDelegate.Invoke(txtres, txtSignalInfo);
            Debug.Log(res);
            //PrintRecvMssgDelegate((PrintRecvMssg),new object[] { txtres, txtSignalInfo });
        }
        catch {
        }
        try
        {
            if (res != null || res !="")
            {
                //接收到数据，连接数据库
                SqlAcces.OpenSql();
                int count_foradd = 0;
                if (SqlAcces.QuerySet(tablesql).Tables[0].Rows.Count > 0)
                {
                    Debug.Log("表存在");
                    idcount = Convert.ToInt32(SqlAcces.QuerySet(tablecountsql).Tables[0].Rows[0][0]);
                    //idcount = SqlAcces.QuerySet(tablesql).Tables[0].Rows.Count;
                    //int count = Convert.ToInt32(data01.Tables[0].Rows[0][0]);
                    DateTime now = GetTime();
                    string string_now = now.ToString();
                    //res的数据格式如下：
                    ///AI8-01,�̦�|AI8-02,�̦�|AI8-03,�̦�|AI8-04,�̦�|AI8-05,�̦�|AI8-06,�̦�|AI8-07,�̦�|AI8-08,�̦�
                    ///0.003576279
                    ///0.003576279
                    ///0.003576279
                    ///0.003576279
                    ///0.003576279
                    ///- 0.003576279
                    ///0.003576279
                    ///0.003576279
                    ///对该数据格式进行处理的步骤如下
                    //1、以\n为分隔符将字符串分割成9份
                    //2、将第一个以“|”分隔符将字符串分割成8份
                    //3、取每一份的前6个字符作为通道
                    //4、将数据插入数据库
                    string[] temps = res.Split('\n');
                    string[] sensing_nums = temps[0].Split('|');
                    int tempcount = 1;
                    foreach (string t in sensing_nums)
                    {
                        string strNum = string.Empty;
                        strNum = t.Substring(0, 6);
                        string[] stri = {idcount + count_foradd + "", string_now, strNum,temps[tempcount]};
                        SqlAcces.InsertInto(tablename, stri);
                        count_foradd++;
                        tempcount++;
                    }                   
                }
                else {
                    Debug.Log($"表{tablename}不存在!");
                    SqlAcces.CreateTable(tablename, CloumName, cloumtype);
                    DateTime now = GetTime();
                    string string_now = now.ToString();
                    string[] temps = res.Split('\n');
                    string[] sensing_nums = temps[0].Split('|');
                    int tempcount = 1;
                    foreach (string t in sensing_nums)
                    {
                        string strNum = string.Empty;
                        strNum = t.Substring(0, 6);
                        string[] stri = { idcount + count_foradd + "", string_now, strNum, temps[tempcount]};
                        SqlAcces.InsertInto(tablename, stri);
                        count_foradd++;
                        tempcount++;
                    }
                }
                SqlAcces.CloseSql();
            }
            
        }
        catch
        {

        }
    }

    //发送“服务器退出提示”
    void sendExit()
    {
        try
        {
            m_bThreadStop = true;
            s.Shutdown(SocketShutdown.Both);
            s.Close();
        }
        catch
        {

        }
    }

    /// <summary>
    /// 启动采样
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public void btnStartSample_Click()
    {
        if (CheckSocket())
            return;

        GetSignalInfo();
        s.Send(DealCmd.GetCmdStartSample());
    }

    /// <summary>
    /// 停止采样
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public void btnStopSample_Click()
    {
        if (CheckSocket())
            return;

        s.Send(DealCmd.GetCmdStopSample());
    }

    //线程内向文本框txtRecvMssg中添加字符串及委托
    private delegate void PrintRecvMssgDelegate(string s1, string s2);
    private void PrintRecvMssg(string info, string signalInfo)
    {
        if (!string.IsNullOrEmpty(info))
        {
            //下面 += 更改为 =，或者直接注释
            string infoText = string.Format("[{0}]:{1}\r\n",
                DateTime.Now.ToLongTimeString(), info);
            infoText += Environment.NewLine;
            Debug.Log(infoText);
        }
        if (!string.IsNullOrEmpty(signalInfo))
        {
            string signalInfoText = "";
            signalInfoText += string.Format("[{0}]:{1}\r\n",
                DateTime.Now.ToLongTimeString(), signalInfo);
            signalInfoText += "---------------------";
            signalInfoText += Environment.NewLine;
            Debug.Log(signalInfoText);
        }
    }

    bool CheckSocket()
    {
        bool res = false;
        if (s == null || s.Connected == false)
        {
            Debug.Log("请点击连接...");
            res = true;
        }
        return res;
    }

    /// <summary>
    /// 获取信号信息
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public void btnGetSignalInfo_Click()
    {
        if (CheckSocket())
            return;
        //cmbSend是窗体
        switch (cmbSend)
        {
            case 0:
                GetSignalInfo();
                break;
            case 1:
                s.Send(DealCmd.GetCmdGetSerialSignal());
                break;
            case 2:
                s.Send(DealCmd.GetCmdGetBlockSignal());
                break;
            case 3:
                s.Send(DealCmd.GetCmdGetStatSignal());
                break;
        }
    }

    void GetSignalInfo()
    {
        s.Send(DealCmd.GetCmdGetSerialSignal());//得到时间序列数据请求
        s.Send(DealCmd.GetCmdGetBlockSignal());//得到块数据请求
        s.Send(DealCmd.GetCmdGetStatSignal());//得到统计数据请求
    }

    public void btnDisConnect_Click()
    {
        sendExit();
        Debug.Log("服务器已断开!");
    }
    //显示时间的函数
    public static DateTime GetTime()
    {
        DateTime now = new DateTime();
        now = DateTime.Now;
        return now;
    }
}

/// <summary>
/// 下面都是对各种数据的定义
/// </summary>
//包数据
public class PackData
{
    public int m_Index;
    public PackHead m_Head;//包数据的头
    /// <summary>
    /// 完整包数据
    /// </summary>
    public List<byte> m_ByteData;

    //命令123的相关信息
    //启动采样前，通知第三方会发送数据的信号信息
    public int m_SignalType;
    public List<string> m_lstSignalName;

    /// <summary>
    /// 位置
    /// </summary>
    public long m_Position;
    /// <summary>
    /// 数据量 每个通道发过来的数据数量
    /// </summary>
    public int m_DataCount;
    /// <summary>
    /// 通道数
    /// </summary>
    public int m_SignalCount;
    /// <summary>
    /// 发来的时间序列数据
    /// </summary>
    public List<float> m_lstSerialSignalData = new List<float>();

    //命令125的相关信息
    /// <summary>
    /// 发来的统计数据
    /// T1V1T2V2T3V3……
    ///通道1时间通道1值通道2时间通道2值通道3时间通道3值……;
    /// </summary>
    public List<StatData> m_lstStatSignalData = new List<StatData>();

    //命令126的相关信息,块数据
    /// <summary>
    /// 信号字符串长度
    /// </summary>
    public int m_SignalNameLength;
    /// <summary>
    /// 信号名
    /// </summary>
    public string m_SignalName;
    /// <summary>
    /// 信号信息
    /// </summary>
    public string m_SignalInfo = "";
    /// <summary>
    /// 数据量 每个通道发过来的数据数量
    /// </summary>
    public int m_SignalInfoLength;
    /// <summary>
    /// 一个数据中包含几个float
    /// </summary>
    public int m_YCount;
    /// <summary>
    /// 发来的块数据
    /// </summary>
    public List<BlockData> m_lstBlockSignalData = new List<BlockData>();
}

//统计数据
public class StatData
{
    public float m_Time;
    public float m_Data;
}
//块数据
public class BlockData
{
    public float m_Time;
    /// <summary>
    /// 一个数据中包含1个float 则使用m_Data1,否则用m_Data1，m_Data2
    /// </summary>
    public float m_Data1;
    public float m_Data2;
}
//包数据的头
public class PackHead
{
    public byte[] m_Signature;//标志位
    public byte[] m_Command;//命令代码
    public byte[] m_Length;//包长度
    public int DataLength;
    public int DataCommand;

    public void Reset()//重置包数据头
    {
        m_Signature = new byte[4];
        m_Command = new byte[4];
        m_Length = new byte[4];
    }
}



